/**
 * 定义XML相关处理器,屏蔽浏览器差异
 *
 * @package js.xml
 * @copyright (c) 2006 - 2007 (www.xidea.org)
 * @author: dawei jin(jindw@xidea.org)
 * @author: DSONet (dsonet@msn.com)
 * @version $Id: mozilla-xml.js 35 2008-03-02 17:01:34Z dsonet $
 */
/**
 * 
 */
var w = window
	, XSLTProcessor = w.XSLTProcessor
	, XPathEvaluator = w.XPathEvaluator
	, DOMParser = w.DOMParser
	, XMLSerializer = w.XMLSerializer
	, XPathResult = w.XPathResult
	, $p;

if (! XPathResult)
{
	/**
	 * @constructor
	 * @param {Object} value
	 * @param {Object} resultType
	 */
	XPathResult = function(value, resultType)
	{
		this.resultType = resultType;

		if (resultType > 7)
		{
			this.singleNodeValue = value;
		}
		else if (resultType > 3)
		{
			this.value = [];

			for (var i = 0; i < value.length; i++)
			{
				this.value.push(value.item(i));
			}
			//}else if(resultType >5){//selectNodes
			this.snapshotLength = value.length;
		}
	}
	XPathResult.prototype =
	{
		/**
		 * This function returns an object that implements the Node interface.
		 * This function can raise an object that implements the XPathException interface or the DOMException interface.
		 */
		iterateNext: function()
		{
			this.values[this.index++];
		},
		/**
		 * This function returns an object that implements the Node interface.
		 * The index parameter is a Number.
		 * This function can raise an object that implements the XPathException interface. 
		 */
		snapshotItem: function(index)
		{
			this.values[index];
		},
		/*The value of the constant XPathResult.ANY_TYPE is */
		ANY_TYPE: 0,
		/*The value of the constant XPathResult.NUMBER_TYPE is */
		NUMBER_TYPE: 1,
		/*The value of the constant XPathResult.STRING_TYPE is */
		STRING_TYPE: 2,
		/*The value of the constant XPathResult.BOOLEAN_TYPE is */
		BOOLEAN_TYPE: 3,
		/*The value of the constant XPathResult.UNORDERED_NODE_ITERATOR_TYPE is */
		UNORDERED_NODE_ITERATOR_TYPE: 4,
		/*The value of the constant XPathResult.ORDERED_NODE_ITERATOR_TYPE is */
		ORDERED_NODE_ITERATOR_TYPE: 5,
		/*The value of the constant XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE is */
		UNORDERED_NODE_SNAPSHOT_TYPE: 6,
		/*The value of the constant XPathResult.ORDERED_NODE_SNAPSHOT_TYPE is */
		ORDERED_NODE_SNAPSHOT_TYPE: 7,
		/*The value of the constant XPathResult.ANY_UNORDERED_NODE_TYPE is */
		ANY_UNORDERED_NODE_TYPE: 8,
		/*The value of the constant XPathResult.FIRST_ORDERED_NODE_TYPE is */
		FIRST_ORDERED_NODE_TYPE: 9
	};
}

if (System.isIE())
{
	if (! XSLTProcessor)
	{ //IE7-
		var xsltemplateProgid = ["MSXML2.XSLTemplate.3.0", "Msxml2.XSLTemplate.6.0"]
			, freeThreadedDOMDocumentProgid = ["MSXML2.FreeThreadedDOMDocument.3.0", "MSXML2.FreeThreadedDOMDocument.6.0"]
			, xmlWriterProgid = ["Microsoft.XMLDOM", "MSXML.MXXMLWriter", "MSXML2.MXXMLWriter", "Msxml2.MXXMLWriter.3.0", "Msxml2.MXXMLWriter.6.0"]
			, domProgid = ["Microsoft.XMLDOM", "MSXML.DOMDocument", "MSXML2.DOMDocument", "Msxml2.DOMDocument.3.0", "Msxml2.DOMDocument.6.0"];

		function createActiveXObject(progIds)
		{
			if (typeof progIds == "string")
			{
				return new ActiveXObject(progIds);
			}
			for (var i = progIds.length - 1, ax; i < progIds.length; i--)
			{
				try
				{
					ax = new ActiveXObject(progIds[i]);
					progIds = progIds[i];
					return ax;
				}
				catch (e)
				{
				}
			}
		}
		/**
		 * Basic implementation of Mozilla's XSLTProcessor for IE. 
		 * Reuses the same XSLT stylesheet for multiple transforms
		 * @constructor
		 */
		XSLTProcessor = function()
		{
			this.template = createActiveXObject(xsltemplateProgid);
		};

		/**
		 * 引入 XSLT 样式表 styleSheet 为 XSLT stylesheet 的根结点
		 * Imports the given XSLT DOM and compiles it to a reusable transform
		 * <b>Note:</b> If the stylesheet was loaded from a URL and contains xsl:import or xsl:include elements,it will be reloaded to resolve those
		 * @argument xslDoc The XSLT DOMDocument to import
		 */
		$p = XSLTProcessor.prototype;
		$p.importStylesheet = function(xslDoc)
		{
			var converted = createActiveXObject(freeThreadedDOMDocumentProgid);
			xslDoc.setProperty("SelectionLanguage", "XPath");
			xslDoc.setProperty("SelectionNamespaces", "xmlns:xsl='http://www.w3.org/1999/XSL/Transform'");

			// make included/imported stylesheets work if exist and xsl was originally loaded from url
			if (xslDoc.url
				&& xslDoc.selectSingleNode("//xsl:*[local-namespaceURI() = 'import' or local-name() = 'include']")
					!= null)
			{
				converted.async = false;

				if (freeThreadedDOMDocumentProgid == "MSXML2.FreeThreadedDOMDocument.6.0")
				{
					converted.setProperty("AllowDocumentFunction", true);
					converted.resolveExternals = true;
				}
				converted.load(xslDoc.url);
			}
			else
			{
				converted.loadXML(xslDoc.xml);
			}
			converted.setProperty("SelectionNamespaces", "xmlns:xsl='http://www.w3.org/1999/XSL/Transform'");
			var output = converted.selectSingleNode("//xsl:output");
			this.outputMethod = output ? output.getAttribute("method") : "html";
			this.template.stylesheet = converted;
			this.processor = this.template.createProcessor();
			// for getParameter and clearParameters
			this.paramsSet = [];
		};

		/**
		 * 使用由importStylesheet()引入的样式表对结点source进行转换. 
		 * Transform the given XML DOM and return the transformation result as a new DOM document
		 * @argument sourceDoc The XML DOMDocument to transform
		 * @return The transformation result as a DOM Document
		 */
		$p.transformToDocument = function(sourceDoc)
		{
			// fix for bug 1549749
			this.processor.input = sourceDoc;
			this.processor.transform();
			var oDoc = createActiveXObject(domProgid);
			oDoc.loadXML(this.processor.output || "");
			return oDoc;
		};
		/**
		 * 使用由importStylesheet()引入的样式表对结点source进行转换，owner 是转换结果的 DOMDocument. 
		 * Transform the given XML DOM and return the transformation result as a new DOM fragment.
		 * <b>Note</b>: The xsl:output method must match the nature of the owner document (XML/HTML).
		 * @argument sourceDoc The XML DOMDocument to transform
		 * @argument ownerDoc The owner of the result fragment
		 * @return The transformation result as a DOM Document
		 */
		$p.transformToFragment = function (sourceDoc, ownerDoc)
		{
			this.processor.input = sourceDoc;
			this.processor.transform();
			var s = this.processor.output;
			var f = ownerDoc.createDocumentFragment();

			if (this.outputMethod == "text")
			{
				f.appendChild(ownerDoc.createTextNode(s));
			}
			else if (ownerDoc.body && ownerDoc.body.innerHTML)
			{
				var container = ownerDoc.createElement("div");
				container.innerHTML = s;

				while (container.hasChildNodes())
				{
					f.appendChild(container.firstChild);
				}
			}
			else
			{
				var oDoc = createActiveXObject(domProgid);

				if (s.substring(0, 5) == "<?xml")
				{
					s = s.substring(s.indexOf("?>") + 2);
				}
				var xml = "".concat("<my>", s, "</my>");
				oDoc.loadXML(xml);
				var container = oDoc.documentElement;

				while (container.hasChildNodes())
				{
					f.appendChild(container.firstChild);
				}
			}
			return f;
		};

		/**
		 * 设置 XSLT stylesheet 的参数
		 * Set global XSLT parameter of the imported stylesheet
		 * @argument namespaceURI The parameter namespace URI
		 * @argument localName The parameter base localName
		 * @argument value The new parameter value
		 */
		$p.setParameter = function(namespaceURI, localName, value)
		{
			// make value a zero length string if null to allow clearing
			value = value || "";
			namespaceURI = namespaceURI || "";

			if (namespaceURI)
			{
				this.processor.addParameter(localName, value, namespaceURI);
			}
			else
			{
				this.processor.addParameter(localName, value);
			};

			// update updated params for getParameter
			if (! this.paramsSet[namespaceURI])
			{
				this.paramsSet[namespaceURI] = {};
			}

			this.paramsSet[namespaceURI][localName] = value;
		};
		/**
		 * 取得 XSLT stylesheet 的参数的值
		 * Gets a parameter if previously set by setParameter. Returns null
		 * otherwise
		 * @argument localName The parameter base name
		 * @argument value The new parameter value
		 * @return The parameter value if reviously set by setParameter, null otherwise
		 */
		$p.getParameter = function(namespaceURI, localName)
		{
			namespaceURI = namespaceURI || "";

			if (this.paramsSet[namespaceURI])
			{
				return this.paramsSet[namespaceURI][localName];
			}
			else
			{
				return null;
			}
		};
		/**
		 * 去除 XSLT stylesheet 中所有参数的值，这将导致 XSLT 使用默认的参数值
		 * Clear parameters (set them to default values as defined in the stylesheet itself)
		 */
		$p.clearParameters = function()
		{
			for (var namespaceURI in processor.paramsSet)
			{
				for (var localName in processor.paramsSet[namespaceURI])
				{
					if (namespaceURI)
					{
						this.processor.addParameter(localName, "", namespaceURI);
					}
					else
					{
						this.processor.addParameter(localName, "");
					};
				};
			};
			this.paramsSet = [];
		};
		/**
		 * 去除 XSLT stylesheet 指定参数的值，这将导致 XSLT 使用默认的参数值
		 */
		$p.removeParameter = function(namespaceURI, localName)
		{
			var params = this.paramsSet[namespaceURI || ""];

			if (params[localName])
			{
				delete params[localName];

				if (namespaceURI)
				{
					this.processor.addParameter(localName, "", nsURI);
				}
				else
				{
					this.processor.addParameter(localName, "");
				};
			}
		}
		/**
		 * 从 XSLTProcessor 中去除所有样式表和参数
		 */
		$p.reset = function()
		{
			this.processor = null;
			this.paramsSet = null;
		}
	}

	if (! DOMParser)
	{
		DOMParser = function(){};

		DOMParser.prototype.parseFromString = function(sXml, contentType)
		{
			var doc = createActiveXObject(domProgid);
			doc.loadXML(sXml);
			return doc;
		};
	}

	if (! XMLSerializer)
	{
		/**
		 * Utility class to serialize DOM Node objects to XML strings
		 * @constructor
		 */
		XMLSerializer = function(){};
		/**
		 * Serialize the given DOM Node to an XML string
		 * @param oNode the DOM Node to serialize
		 */
		XMLSerializer.prototype.serializeToString = function(oNode)
		{
			return oNode.xml;
		};
	}

	if (! XPathEvaluator)
	{
		/**
		 * @constructor
		 */
		XPathEvaluator = function(){};

		XPathEvaluator.prototype.evaluate = function(expression, contextNode, resolver, type, result)
		{
			if (type > 7)
			{ //ANY_UNORDERED_NODE_TYPE:8,FIRST_ORDERED_NODE_TYPE:9
				var value = contextNode.selectSingleNode(expression);
			}
			else
			{
				var value = contextNode.selectNodes(expression);
			}
			return new XPathResult(value, type);
		}
		XPathEvaluator.selectSingleNode = function(contextNode, expression)
		{
			return contextNode.selectSingleNode(expression);
		};
		XPathEvaluator.selectNodes = function(contextNode, expression)
		{
			return contextNode.selectNodes(expression);
		};
	}
} //end ie
else
{
	if (XPathEvaluator)
	{

		function getItem (index)
		{
			return this[index];
		}

		XPathEvaluator.selectSingleNode = function(contextNode, expression)
		{
			var evaluator = new XPathEvaluator();
			var result = evaluator.evaluate(expression, contextNode, null, 9, null);
			return result ? result.singleNodeValue : null;
		};
		XPathEvaluator.selectNodes = function(contextNode, expression)
		{
			//ORDERED_NODE_ITERATOR_TYPE:5,
			var evaluator = new XPathEvaluator();
			var result = evaluator.evaluate(expression, contextNode, null, 5, null);
			var nodeList = [];
			var item;

			while (item = result.iterateNext())
			{
				nodeList.push(item);
			}
			nodeList.item = getItem;
			return nodeList;
		};
	}
	else if (document.selectSingleNode)
	{
		XPathEvaluator = function(expression, contextNode, resolver, type, result)
		{
			if (type > 7)
			{ //ANY_UNORDERED_NODE_TYPE:8,FIRST_ORDERED_NODE_TYPE:9
				var value = XPathEvaluator.selectSingleNode(contextNode, expression);
			}
			else
			{
				var value = XPathEvaluator.selectNodes(contextNode, expression);
			}
			return new XPathResult(value, type);
		};
		XPathEvaluator.selectSingleNode = function(contextNode, expression)
		{
			var doc = contextNode.ownerDocument;

			if (contextNode.selectSingleNode)
			{
				return contextNode.selectSingleNode(expression);
			}
			else if (doc.selectSingleNode)
			{
				return doc.selectSingleNode(expression, contextNode);
			}
		};
		XPathEvaluator.selectNodes = function(contextNode, expression)
		{
			var doc = contextNode.ownerDocument;

			if (contextNode.selectNodes)
			{
				return contextNode.selectNodes(expression);
			}
			else if (doc.selectNodes)
			{
				return doc.selectNodes(expression, contextNode);
			}
		};
	}

	if (! DOMParser)
	{
		if (System.isKhtml() || System.isOpera(7.2))
		{
			/**
			 * DOMParser is a utility class, used to construct DOMDocuments from XML strings
			 * @constructor
			 */
			DOMParser = function(){};
			/** 
			 * Construct a new DOM Document from the given XMLstring
			 * @param sXml the given XML string
			 * @param contentType the content type of the document the given string represents (one of text/xml, application/xml, application/xhtml+xml). 
			 * @return a new DOM Document from the given XML string
			 */
			DOMParser.prototype.parseFromString = function(sXml, contentType)
			{
				var xmlhttp = new XMLHttpRequest;
				xmlhttp.open("GET", "data:text/xml;charset=utf-8," + encodeURIComponent(sXml), false);
				if (contentType && xmlhttp.overrideMimeType) {
					xmlhttp.overrideMimeType(contentType);
				}
				xmlhttp.send(null);
				return xmlhttp.responseXML;
			};
		}
	}
}
$p = w = null;